package server

import (
	"errors"
	"fmt"
	"github.com/spf13/cast"
	"golang.org/x/net/context"
	"longmen/server/config/global"
	"longmen/server/pkg/common/api_models"
	"longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/common/payment/client"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	pb "longmen/server/pkg/protobuf"
	"strings"
	"time"
)

/**
 * @Description //慧收钱
 **/
func (s *Server) ApplyHsqPayment(ctx context.Context, req *pb.OrderNoReq) (*pb.HsqBusinessResp, error) {
	orderNo, _ := util.CreatePaymentOrderNo(_const.PAYMENT_PREFIX_HSQ)
	payChannel := _const.PAY_CHANNEL_WECHAT
	if req.PayType == _const.HSQ_DYNAMIC_ALPAY || req.PayType == _const.HSQ_NATIVE_ALI {
		payChannel = _const.PAY_CHANNEL_ALPAY
	}
	//终端类型
	if req.Terminal == 0 {
		req.Terminal = _const.TERMINAL_ANDROID
	} else {
		req.Terminal = _const.TERMINAL_PC
	}
	if db_main.InsertAndroidPaymentApply(req, orderNo, int(req.Terminal), payChannel) > 0 {
		if paymentApply, err := db_main.GetPaymentOrderNo(int(req.UserId), orderNo); err == nil {
			if api := GetPaymentApi(_const.PAYMENT_HSQ_CODE); api != nil {
				return client.HsqApply(createBusinessReq(api, req, paymentApply))
			}
		}
	}
	return nil, errors.New("申请充值失败")
}

/**
 * @Author willi
 * @Description //TODO
 * @Date 14:12 2022/9/5
 * @Param
 * @return
 **/
func (s *Server) HsqPaymentCallBack(ctx context.Context, hsqReq *pb.HsqBasic) (*pb.HsqPaymentCallBackResp, error) {
	ret := &pb.HsqPaymentCallBackResp{Code: _const.RPC_FAILED}
	if api := GetPaymentApi(_const.PAYMENT_HSQ_CODE); api != nil {
		if back, err := client.HsqPayCallBack(hsqReq, api); err == nil {
			if strings.EqualFold(back["orderStatus"], "SUCCESS") {
				productPayReq := createHspProductPayReq(back)
				product := commitPayOrder(_const.PAY_SUCCESS, productPayReq)
				ret.Code = product.Code
			} else if strings.EqualFold(back["orderStatus"], "FAIL") {
				productPayReq := createHspProductPayReq(back)
				product := commitPayOrder(_const.PAY_FAIL, productPayReq)
				ret.Code = product.Code
			}
		}
	}

	return ret, nil
}

func createHspProductPayReq(back map[string]string) *pb.ProductPayReq {
	productPayReq := &pb.ProductPayReq{}
	productPayReq.TransactionId = back["tradeNo"]
	productPayReq.UserId = cast.ToInt64(back["extend"])
	productPayReq.OrderNo = back["transNo"]
	productPayReq.OrderAmt = cast.ToInt64(back["orderAmt"])
	return productPayReq
}
func commitPayOrder(PayStatus int, productPayReq *pb.ProductPayReq) *pb.ProductPayResp {
	//开始支付 开始事务
	payResp := &pb.ProductPayResp{Code: _const.RPC_FAILED}
	session := global.GetX().Begin()
	//
	if db_main.UpdateOtherPaymentApplyStatus(session, productPayReq, PayStatus) == 0 {
		payResp.Code = _const.RPC_FAILED
		session.Rollback()
		return payResp
	}
	if PayStatus == _const.PAY_SUCCESS {
		paymentApply, _ := db_main.GetPaymentOrderNo(int(productPayReq.UserId), productPayReq.OrderNo)
		if _, afterAmount, err := db_main.UpdateAmountByTx(int(paymentApply.UserId), int(paymentApply.GoldIos+paymentApply.GoldAdded), _const.CoinDiamond, session, _const.WALLET_BALANCE_SHOW, produceProfit(paymentApply)); err == nil {
			payResp.Code = _const.RPC_SUCCEED
			payResp.Balance = int64(afterAmount)
		} else {
			session.Rollback()
			payResp.Code = _const.RPC_FAILED
			return payResp
		}
	}
	//提交事务
	if err := session.Commit().Error; err != nil {
		session.Rollback()
		payResp.Code = _const.RPC_FAILED
	}
	return payResp
}
func createBusinessReq(api *models_main.PaymentApi, req *pb.OrderNoReq, paymentApply *pb.PaymentApply) *api_models.HsqBusinessReq {
	param := &api_models.HsqBusinessReq{}

	param.PayType = req.PayType
	param.OrderAmt = cast.ToString(paymentApply.Price)
	//param.OrderAmt = cast.ToString(1)
	param.GoodsInfo = paymentApply.ItemCarat
	param.PageUrl = _const.EMPTY_STR
	param.ReturnUrl = api.ApiParams
	param.ApiHost = api.ApiHost
	param.Extend = cast.ToString(paymentApply.UserId)
	param.Memo = "charge money"
	param.TransNo = paymentApply.OrderNo
	param.SpbillCreateIp = req.ClientIp
	param.MerchantNo = api.ApiAccount
	param.ApiKey = api.ApiKey
	param.ApiSecret = api.ApiSecret
	param.Terminal = req.Terminal
	param.AppId = api.AppId
	return param
}

func GetPaymentApi(apiCode string) *models_main.PaymentApi {
	//先从缓存中取数据
	paymentApi := &models_main.PaymentApi{}
	cacheKey := generateCacheKey(apiCode)
	if err := getRedisCache(paymentApi, cacheKey); err != nil {
		paymentApi = db_main.GetPaymentApi(apiCode)
		setRedisCache(paymentApi, cacheKey, _const.PAYMENT_CACHE_EXPIRY_TIME)
	}
	return paymentApi
}

/**
* @Author:admin
* @Description:从redis 取一个联赛菜单列表
* @Param :
* @Return :
* @Date: 9:46 2022/6/22
 */
func getRedisCache(paymentApi *models_main.PaymentApi, key string) error {

	if data, err := global.GetRds().Get(key).Result(); err == nil {
		return util.Json2Struct(data, &paymentApi)
	} else {
		return err
	}
}

/**
 * @Author admin
 * @Description //
 * @version: v1.8.0
 * @Date 18:26 2022/8/18
 * @Param
 * @return
 **/
func setRedisCache(obj interface{}, key string, expiry int) error {

	cacheData, _ := util.Struct2Json(obj)
	global.GetRds().Set(key, cacheData, time.Duration(expiry)*time.Second)
	return nil
}

func generateCacheKey(key string) string {

	return fmt.Sprintf("%s%s", _const.PAYMENT_CACHE_PRE, key)
}
